/*
 * ZENworks Notification Icon
 * Copyright (C) Author: Gangadhar Nagesh Metla (Novell, Inc.)
 * nmetla74@gmail.com 
 * Version 1.0
 * 1/3/2009
 * Filename ZTrayIcon.java
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package com.novell.zenworks.agent.zicon;

import java.io.File;
import java.io.IOException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolTip;
import org.eclipse.swt.widgets.Tray;
import org.eclipse.swt.widgets.TrayItem;

import com.novell.zenworks.agent.common.Paths;
import com.novell.zenworks.agent.common.ICommonUIEnums.MB_CHECKBOX;
import com.novell.zenworks.agent.common.ICommonUIEnums.MB_ICON;
import com.novell.zenworks.agent.common.ICommonUIEnums.MB_RESPONSE;
import com.novell.zenworks.agent.common.ICommonUIEnums.MB_TYPE;
import com.novell.zenworks.agent.zbrowser.MessageBoxLauncher;
import com.novell.zenworks.ipc.remoting.RemotingConstants;
import com.novell.zenworks.ipc.remoting.RemotingUtility;
import com.novell.zenworks.zicon.common.HTMLPage;
import com.novell.zenworks.zicon.common.IZenIconMenuItem;
import com.novell.zenworks.zicon.common.IZenIconMenuItemGroup;
import com.novell.zenworks.zicon.common.IZenModuleServer;
import com.novell.zenworks.zicon.common.LogUtil;
import com.novell.zenworks.zicon.common.ResourceManager;

/**
 * ZENworks System Tray Icon.
 */
public class ZTrayIcon
{
    public final Display display;  //display variable for zicon
    public final Shell shell;      //shell for storing menu
    public Image image;      //zenworks system tray icon image
    public final Tray tray;        //system tray
    public final TrayItem item;    //system tray item
    public Menu menu = null;       //zenworks icon context menu
    public ToolTip menuTip = null; //tool tip
    public static HTMLPage propertyPage = null;      //property page info
    public static final ResourceManager rm = ResourceManager.getInstance();
    public static ZTrayIcon _instance = null; //instance of ZTrayIcon
    private static Object lock = new Object(); //for synchronization
    
    public static ZTrayIcon getInstance() throws Exception
    {
        if(_instance == null)
        {
            synchronized(lock)
            {
                if(_instance == null)
                {
                    _instance = new ZTrayIcon();
                    _instance.initialize();
                }
            }
        }
       return _instance;
    }
    
    public ZTrayIcon() throws Exception
    {
        display = new Display();
        shell = new Shell(display);
        image = new Image(display, ZTrayIcon.getImagesPath() + File.separator + "Application.ico");
        tray = display.getSystemTray();
        item = new TrayItem(tray, SWT.NONE);
        propertyPage = new HTMLPage("Status", "Status", "property"); //TODO make use of enums.
    }
    
    public void initialize() throws Exception
    {
        item.setToolTipText(rm.getString("SysTrayIconText"));
        
        if (tray == null)
        {
            throw new Exception(rm.getString("SystemTrayError"));
        } 
        else
        {
            addTrayItemEventListeners();          
            item.setImage(image);
            item.setVisible(true);
        }
    }
    
    public boolean getVisible()
    {
        return item.getVisible();
    }
    
    public void setVisible(boolean isVisible)
    {
        ZiconConfigurator showZIcon = new ZiconConfigurator(item, isVisible);
        display.asyncExec(showZIcon);
    }
    
    public void showBalloonTip(String message, String title, MB_ICON iconType, int timeout)
    {
        BalloonMessage msg = new BalloonMessage(shell, item, message, title, iconType, timeout);
        display.asyncExec(msg);        
    }
    
    public boolean addMenuItems(Menu menu, List<IZenIconMenuItem> mid, boolean separator) throws Exception
    {
        boolean success = false;
        if(menu != null && mid != null)
        {
            for(int i=0; i<mid.size(); i++)
            {
                MenuItem mi = null;
                if(mid.get(i).getSubItems() != null)
                {
                    mi = new MenuItem(menu, SWT.CASCADE);
                }
                else if(mid.get(i).getCheckboxType().equals(MB_CHECKBOX.MBC_RADIO))
                {
                    mi = new MenuItem(menu, SWT.RADIO);
                }
                else if(mid.get(i).getCheckboxType().equals(MB_CHECKBOX.MBC_CHECK))
                {
                    mi = new MenuItem(menu, SWT.CHECK);
                }
                else
                {
                    mi = new MenuItem(menu, SWT.PUSH);
                }
                mi.setText(mid.get(i).getText());
                mi.setEnabled(mid.get(i).isEnabled());
                mi.setData(mid.get(i));
                mi.setImage(getImage(mid.get(i).getIconPath()));
                mi.setAccelerator(getAcclKey(mid.get(i).getShortcutKeys()));
                mi.addListener(SWT.Selection, new Listener()
                {
                    public void handleEvent(Event e)
                    {
                        try
                        {
                            IZenIconMenuItem zim = (IZenIconMenuItem) e.widget.getData();
                            MenuItemHandler handler = new MenuItemHandler(zim);
                            handler.handleMenuItem();
                        } catch (Exception e1)
                        {
                            try
                            {
                                LogUtil.LogException(e1.getMessage(), e1);
                                MessageBoxLauncher.ShowMessageBoxHandler(ZTrayIcon.rm.getString("RemotingError"), ZTrayIcon.rm.getString("PropDlgTitle") , MB_TYPE.MBT_OK, MB_ICON.MBI_ERROR, 30, false, MB_RESPONSE.MBR_OK);
                            } catch (Exception e2)
                            {
                                LogUtil.LogException(e1.getMessage(), e2);
                            }
                        }
                    }
                });
                
                if(mid.get(i).getSubItems() != null && mid.get(i).getSubItems().size() > 0)
                {
                    Menu subMenu = new Menu(shell, SWT.DROP_DOWN);
                    for(int j=0; j<mid.get(i).getSubItems().size(); j++)
                    {
                         addMenuItems(subMenu, mid.get(i).getSubItems(), false);
                    }
                    mi.setMenu(subMenu);
                }
            }  
            
            if(separator)
            {
                new MenuItem(menu, SWT.SEPARATOR);
            }
            success = true;
        }            
        return success;       
    }
    
    public void startAnimation()
    {  
        Animator anim = Animator.getInstance();
        anim.setStop(false);
        display.asyncExec(anim);
    }
    
    public void stopAnimation()
    {
        try 
        {
        	Animator.getInstance().setStop(true);
			PageApp.refreshPage();
		} catch (Exception e) 
		{
			try
            {
                LogUtil.LogException(e.getMessage(), e);
                if(e.getMessage() != null)
                    MessageBoxLauncher.ShowMessageBoxHandler(e.getMessage(), ZTrayIcon.rm.getString("PropDlgTitle") , MB_TYPE.MBT_OK, MB_ICON.MBI_ERROR, 30, false, MB_RESPONSE.MBR_OK);
            } catch (Exception e1)
            {
                LogUtil.LogException(e.getMessage(), e1);
            }

		}
    }
    
    private void addTrayItemEventListeners()
    {
        item.addListener(SWT.Selection, new Listener()
        {
            public void handleEvent(Event event)
            {                
                try
                {
                    PageApp.launchBrowser(propertyPage.getId());
                } catch (Exception e)
                {
                    try
                    {
                        LogUtil.LogException(e.getMessage(), e);
                        MessageBoxLauncher.ShowMessageBoxHandler(ZTrayIcon.rm.getString("RemotingError"), ZTrayIcon.rm.getString("PropDlgTitle") , MB_TYPE.MBT_OK, MB_ICON.MBI_ERROR, 30, false, MB_RESPONSE.MBR_OK);
                    } catch (Exception e1)
                    {
                        LogUtil.LogException(e.getMessage(), e1);
                    }
                }
            }
        });
        item.addListener(SWT.DefaultSelection, new Listener()
        {
            public void handleEvent(Event event)
            {
                try
                {
                    PageApp.launchBrowser(propertyPage.getId());
                } catch (Exception e)
                {
                    try
                    {
                        LogUtil.LogException(e.getMessage(), e);
                        MessageBoxLauncher.ShowMessageBoxHandler(ZTrayIcon.rm.getString("RemotingError"), ZTrayIcon.rm.getString("PropDlgTitle") , MB_TYPE.MBT_OK, MB_ICON.MBI_ERROR, 30, false, MB_RESPONSE.MBR_OK);
                    } catch (Exception e1)
                    {
                        LogUtil.LogException(e.getMessage(), e1);
                    }
                }
            }
        });
        
        item.addListener(SWT.MenuDetect, new Listener()
        {
            public void handleEvent(Event event)
            {
                menu = new Menu(shell, SWT.POP_UP);
                try
                {
                    fetchMenuItems();
                } catch (Exception e)
                {
                    try
                    {
                        LogUtil.LogException(e.getMessage(), e);
                        MessageBoxLauncher.ShowMessageBoxHandler(ZTrayIcon.rm.getString("RemotingError"), ZTrayIcon.rm.getString("PropDlgTitle") , MB_TYPE.MBT_OK, MB_ICON.MBI_ERROR, 30, false, MB_RESPONSE.MBR_OK);
                    } catch (Exception e1)
                    {
                        LogUtil.LogException(e.getMessage(), e1);
                    }
                }
                menu.setVisible(true);
            }
        });
    }
    
    public void dispose()
    {
        image.dispose();
        display.dispose();
    }
    
    public Image getImage(String location)
    {
        //TODO try invalid location and catch the exception.
        Image img = null;
        if(location != null)
        {
            img = new Image(display, location);
        }
        return img;        
    }
    
    public int getAcclKey(String key)
    {
       int acclKey = 0;
       if(key != null)
       {
           StringTokenizer tokens = new StringTokenizer(key);
           while(tokens.hasMoreTokens())
           {
               String token = tokens.nextToken("+");
               if(token.equalsIgnoreCase("CTRL"))
               {
                   acclKey += SWT.CTRL;
               }
               else if(token.equalsIgnoreCase("ALT"))
               {
                   acclKey += SWT.ALT;
               }
           }

           acclKey += key.charAt(key.length()-1);
       }
       
       return acclKey;
    }
    
    public Display getDisplay()
    {
        return display;
    }

    public Shell getShell()
    {
        return shell;
    }

    public Image getImage()
    {
        return image;
    }

    public Tray getTray()
    {
        return tray;
    }

    public TrayItem getItem()
    {
        return item;
    }

    public Menu getMenu()
    {
        return menu;
    }
    
    public static String getImagesPath() throws Exception
    {
        String path = null;
        String osName = System.getProperty("os.name");
        if(osName.toLowerCase().contains("mac"))
        {
            path = Paths.RESOURCE_DIR + File.separator + "images" + File.separator + "zicon" + File.separator + "mac";
        }
        else //use linux images for other platforms until there is a platform specific requirement.
        {
            path = Paths.RESOURCE_DIR + File.separator + "images" + File.separator + "zicon" + File.separator + "linux";
        }
        return path;
    }
    
    public static IZenModuleServer getServer() throws RemoteException, NotBoundException
    {
        return (IZenModuleServer) RemotingUtility.getRemoteObject(RemotingConstants.ZICON_REMOTING_ID);
    }

    private void fetchMenuItems() throws Exception
    {
        IZenIconMenuItemGroup[]  grps = getServer().getMenuGroups(Locale.getDefault().getLanguage(),Locale.getDefault().getCountry());        
        
        if(grps == null) //Temp: This will be removed after backend throws exception if menu items are not found.
        {
            throw new Exception("There are no menu items"); //TO DO Localization.
        }
        
        for(int i=0; i<grps.length; i++)
        {       
            addMenuItems(menu, grps[i].getMenuItems(), grps[i].isUseSeparator());
        }
    }
    
    public static void launchHelpFile(String file)
    {
        boolean success = false;
        success = org.eclipse.swt.program.Program.launch(file);
        
        //directly launch with firefox.
        if(!success)
        {
            try
            {
                Runtime.getRuntime().exec("firefox "+ file);
            } catch (IOException e)
            {
                try
                {
                	//for RHEL4
                	LogUtil.LogException(e.getMessage(), e);
                	Runtime.getRuntime().exec("konqueror "+ file);
                } catch (Exception e1)
                {
                	LogUtil.LogException(e1.getMessage(), e1);
                	try 
                	{
                		MessageBoxLauncher.ShowMessageBoxHandler(e.getMessage(), ZTrayIcon.rm.getString("PropDlgTitle") , MB_TYPE.MBT_OK, MB_ICON.MBI_ERROR, 30, false, MB_RESPONSE.MBR_OK);
                	} catch (Exception e2) 
                	{
                		LogUtil.LogException(e2.getMessage(), e2);
                	}
                }   
            }
        }
    }

	public static void launchTextFile(String editor, String filePath) {
		try {
			Runtime.getRuntime().exec(editor + " "+ filePath);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
    
}
